#ifndef PDFVIEWER_H
#define PDFVIEWER_H

#include <QtGui>
#include <poppler-qt4.h>

#include "annotation.h"
#include "reportwidget.h"
#include "rendercachekey.h"

class NoteWidget;

namespace Ui {
class PDFViewer;
}

class PDFTextBox
{
public:
	int pageNumber;
	int id; // unique for the current page
	int nextId; // or -1
	// in 0-1 non-cropped page coords
	QRectF bbox;
	QString text;
	bool isHighlighted;
	QColor highlightColor;
};

class PDFUrlLink
{
public:
	PDFUrlLink(int pageNumber, QString url, QRectF clickArea)
		: pageNumber(pageNumber), url(url), clickArea(clickArea) {
	}

	int pageNumber;
	QString url;
	QRectF clickArea;
};

class PDFJumpLink
{
public:
	PDFJumpLink(int pageNumber, int destPageNumber, QPointF destPoint, QRectF clickArea)
		: pageNumber(pageNumber),
		  destPageNumber(destPageNumber),
		  destPoint(destPoint),
		  clickArea(clickArea) {
	}

	int pageNumber;
	int destPageNumber;
	QPointF destPoint;
	QRectF clickArea;
};

class PDFViewer : public QWidget
{
	Q_OBJECT

	enum ViewMode {
		SinglePage = 0,
		TwoPages = 1,
		Slideshow = 2
	};
	
public:
	explicit PDFViewer(QWidget *parent = 0);
	~PDFViewer();

	void loadDocument(QString fileName,
					  QByteArray docHash,
					  QHash<RenderCacheKey, QPair<QImage, qint64> > pageCache = QHash<RenderCacheKey, QPair<QImage, qint64> >(),
					  bool reloading = false);
	QString getFileName();
	bool isImportable();
	QByteArray getDocHash();

	bool tryCreateInterDocAnchor(QByteArray docHash, int pageNumber, QPointF normalizedPos, QString reference);

public slots:
	void setFullScreen(bool value);
	void onShowControls(bool value);
	void setControlsVisible(bool value);
	void setImportable(bool value);
	void createTextNote(TextNoteAnnotation note);
	void deleteTextNote(int id);

	void setReportText(QString text);

	void createTextHighlight(HighlightAnnotation h);
	void deleteTextHighlight(int pageNumber, QRectF rect);

	QSizeF getAvailablePageSize();

	void onNavigationRequested(int pageNumber, QPointF normPos);
	void setViewOffset(qreal offsetNormalized);

	void setSuggestedFileName(QString saveName);

	void showDocInfo(QString docInfo);
	QHash<RenderCacheKey, QPair<QImage, qint64> > getRenderCache();

signals:
	void showControls(bool value);
	void controlsVisibleToggled(bool value);
	void fullScreenToggled(bool value);
	void importClicked(QString fileName);

	void textNoteCreationRequested(PDFViewer *v, QByteArray docHash, int pageNumber, QPointF pos, QColor color);
	void textNoteDeleteRequested(PDFViewer *v, QByteArray docHash, int id);
	void textNoteTitleChanged(PDFViewer *v, QByteArray docHash, int id, QString title);
	void textNoteTextChanged(PDFViewer *v, QByteArray docHash, int id, QString text);
	void textNotePosChanged(PDFViewer *v, QByteArray docHash, int id, QPointF pos);
	void textNoteColorChanged(PDFViewer *v, QByteArray docHash, int id, QColor color);
	void textNoteMaximizedChanged(PDFViewer *v, QByteArray docHash, int id, bool value);
	void textNoteMaxSizeChanged(PDFViewer *v, QByteArray docHash, int id, QSize maxSize);
	void reportTextChanged(PDFViewer *v, QByteArray docHash, QString text);

	void highlightCreationRequested(PDFViewer *v, QByteArray docHash, int pageNumber, QRectF box, QColor color);
	void highlightDeletionRequested(PDFViewer *v, QByteArray docHash, int pageNumber, QRectF box);

	void interDocumentAnchorRequested(PDFViewer *v, QByteArray docHash, int pageNumber, QPointF normalizedPos);
	void navigationRequested(QByteArray docHash, int pageNumber, QPointF normPos);

	void viewOffsetCHanged(QByteArray docHash, qreal viewOffsetNormalized);

	void docInfoRequested(PDFViewer *v, QByteArray docHash);
	void pageCacheChanged(PDFViewer *v, QByteArray docHash);

protected:
	void resizeEvent(QResizeEvent *e);
	void showEvent(QShowEvent *e);
	bool eventFilter(QObject *obj, QEvent *event);

protected slots:
	void render();
	// if it is not computed, if useDefault is set it returns a default rect, otherwise it returns a null rect
	QRectF getPageBBox(int iPage, bool useDefault, bool *returnedDefault = NULL);
	void startRenderAsync1(int iPage);
	void renderAsync1(int iPage);
	void onRenderSync1(int iPage);
	void startRenderAsync2(int iPage, QSizeF resolution, QRect rect);
	void renderAsync2(int iPage, QSizeF resolution, QRect cropRect);
	void onRenderSync2(int iPage, QImage image);
	void relayout();
	void mousePoll();

	// notes
	void noteDeleteRequested(QByteArray docHash, int id);
	void noteTitleChanged(QByteArray docHash, int id, QString title);
	void noteTextChanged(QByteArray docHash, int id, QString text);
	void notePosChanged(QByteArray docHash, int id, QPoint pos);
	void noteColorChanged(QByteArray docHash, int id, QColor color);
	void noteMaximizedChanged(QByteArray docHash, int id, bool value);
	void noteMaxSizeChanged(QByteArray docHash, int id, QSize maxSize);
	void onReportTextChanged(QString text);

	QPointF normalizedPos2WidgetPos(int pageNumber, QPointF normPos);
	QPointF widgetPos2NormalizedPos(int pageNumber, QPointF widgetPos);
	QRectF normalizedRect2WidgetRect(int pageNumber, QRectF normRect);
	QRectF widgetRect2NormalizedRect(int pageNumber, QRectF widgetRect);
	int textBoxFromNormCoords(int pageNumber, QPointF normPos);

	void onNavigationRequested(QByteArray docHash, int pageNumber, QPointF normPos);

	void setAbortAllRendering(bool value);
	bool getAbortAllRendering();

	QImage getImageFromCache(int pageNumber, QRect cropRect, QSizeF resolution);
	void addImageToCache(int pageNumber, QRect cropRect, QSizeF resolution, QImage image);
	
private slots:
	void scrollValueChanged(int value);
	void scrollRangeChanged(int min, int max);
	void on_btnSinglePage_toggled(bool checked);
	void on_btnSlideshow_toggled(bool checked);
	void on_btnTwoPages_toggled(bool checked);
	void on_btnMinBorder_toggled(bool checked);
	void on_btnFullScreen_toggled(bool checked);
	void clearFinishedJobs();
	void on_btnOpenOutside_clicked();
	void on_btnImport_clicked();

	void on_btnReplaceFonts_toggled(bool checked);
	void highlightCursor();
	void on_btnHighlightYellow_toggled(bool checked);
	void on_btnHighlightGreen_toggled(bool checked);
	void on_btnHighlightRed_toggled(bool checked);
	void on_btnHighlightPink_toggled(bool checked);
	void on_btnHighlightBlue_toggled(bool checked);
	void on_btnSaveOutside_clicked();

	void onReportSnapBottomRequested();
	void onReportSnapRightRequested();

	void on_splitter_splitterMoved(int pos, int index);
	void on_btnReport_toggled(bool checked);

	void on_btnSaveOutsideAnnotated_clicked();

	void redrawScrollBarBg();
	void updatePageNumber();

	void on_btnDocInfo_clicked();

	void tryWatchFile();
	void onFileChanged(const QString &path);
	void onDelayedFileChanged();
	void reload();

	void on_btnShowControls_toggled(bool checked);

	void onHideJumpTarget();

signals:
	void renderSync1(int iPage);
	void renderSync2(int iPage, QImage image);

private:
	Ui::PDFViewer *ui;
	QString fileName;
	QByteArray docHash;
	Poppler::Document* document;
	QList<QLabel *> pixPages;
	QList<QSizeF> pdfPageSizes;
	QList<QRectF> pageBBoxes;
	QList<QMutex*> pageBBoxes_pageMutex;
	QList<bool> pageShouldRender;
	QMutex* pageBBoxes_mutex;
	QMutex* documentMutex;
	QMutex* signalingMutex;
	bool abortAllRendering;
	QList<bool> rendererPageMask;
	QMutex *rendererPageMask_mutex;
	QList<QFuture<void> > runningJobs;
	// page -> list of text boxes
	QHash<int, QList<PDFTextBox> > textBoxes;
	QHash<NoteWidget*, bool> noteWidgets;
	QHash<int, QList<TextAnchor> > anchors;
	QList<QPixmap> localAnchorPixmaps;
	QList<QPixmap> interAnchorPixmaps;
	// page -> links
	QHash<int, QList<PDFUrlLink> > pageLinks;
	QHash<int, QList<PDFJumpLink> > pageJumpLinks;
	TextAnchor jumpAnchor;
	ViewMode viewMode;
	bool crop;
	qreal maxCropFraction;
	QString suggestedFileName;
	// minimum page border in points (at the poppler default DPI, i.e. 72)
	// should be >= 2 due to rounding errors/AA
	int minBorder;
	int shadowSize;
	int preRenderDistance;
	QPair<int, int> oldRange;
	bool navigationPending;
	qreal navigationOffset;
	bool firstRenderReady;
	QFileSystemWatcher fileWatcher;
	bool delayedFileChangedTriggered;
	bool moreFileChangedTriggered;
	// page, crop rect, size -> image
	QMutex *renderCacheMutex;
	QHash<RenderCacheKey, QPair<QImage, qint64> > renderCache;
	// TODO limit cache, now it grows to inifinite
};

#endif // PDFVIEWER_H
